/*
	ViewOptions.cpp
	(c)2000 Palestar, Richard Lyle
*/

#include "Debug/Assert.h"
#include "System/Keyboard.h"
#include "Standard/Settings.h"
#include "Interface/ViewOptions.h"

//----------------------------------------------------------------------------

struct Mapping
{
	const char *	pName;
	dword			key;
};

static Mapping KEYBOARD_MAP[] = 
{
	{ "Help",							HK_F1 },
	{ "Navigation",						HK_F2 },
	{ "Planets",						HK_F3 },
	{ "Communications Log",				HK_F4 },
	{ "Profile",						HK_F5 },
	{ "Mission",						HK_F6 },

	{ "Turn Left",						'A' },
	{ "Stop Turn",						'S' },
	{ "Turn Right",						'D' },
	{ "Increase Velocity",				'W' },
	{ "Decrease Velocity",				'Q' },
	{ "Zoom In",						'Z' },
	{ "Zoom Out",						'X' },
	{ "Chat",							HK_RETURN },
	{ "Decrease contact range",			219 },
	{ "Increase contact range",			221 },
	{ "Toggle Shield/Turn Display",		191 },
	{ "Toggle Ship Status Display",		HK_NUMPAD7 },
	{ "Toggle Group Display",			HK_NUMPAD9 },
	{ "Toggle Left Console",			HK_NUMPAD1 },
	{ "Toggle Right Console",			HK_NUMPAD3 },
	{ "Toggle Camera Mode",				HK_TAB },

	{ "Follow",							'F' },
	{ "Orbit",							'O' },
	{ "Dock",							'G' },
	{ "Load",							'L' },
	{ "Unload",							'U' },

	{ "Next Enemy Target",				'E' },
	{ "Closest Enemy Target",			HMK_SHIFT_MASK | 'E' },
	{ "Next Friendly Target",			'R' },
	{ "Closest Friendly Target",		HMK_SHIFT_MASK | 'R' },
	{ "Closest Supply/Depot",			HMK_CONTROL_MASK | 'R' },
	{ "Closest Friendly Jumpgate",		HMK_CONTROL_MASK | 'J' },
	{ "Target Last Distress",			'H' },
	{ "Send Distress",					HMK_CONTROL_MASK | 'H' },
	{ "Send Supply Distress",			HMK_SHIFT_MASK | 'H' },
	{ "Self Destruct",					HMK_CONTROL_MASK | 'D' },
	{ "Request Mission",				HMK_CONTROL_MASK | 'O' },
	{ "Abort Mission",					HMK_CONTROL_MASK | 'A' },

	{ "Toggle Point Defense",			HMK_CONTROL_MASK | 'B' },

	{ "Tractor Beam",					'T' },
	{ "Repulsor Beam",					HMK_SHIFT_MASK | 'T' },
	{ "Mining Beam",					'G' },
	{ "Bombs",							'B' },
	{ "Explode Bombs",					HMK_SHIFT_MASK | 'B' },
	{ "Jump Drive",						'J' },
	{ "Emergency Jump",					HMK_SHIFT_MASK | 'J' },
	{ "ECM/Cloak",						'K' },
	{ "ECCM",							'P' },
	{ "Reload",							'Y' },
	{ "Fighters",						'N' },
	{ "Recall Fighters",				HMK_SHIFT_MASK | 'N' },

	{ "Increase Full Shields",			HK_NUMPAD5 },
	{ "Increase Front Shields",			HK_NUMPAD8 },
	{ "Increase Right Shields",			HK_NUMPAD6 },
	{ "Increase Aft Shields",			HK_NUMPAD2 },
	{ "Increase Left Shields",			HK_NUMPAD4 },
	{ "Toggle All Shields",				HMK_CONTROL_MASK | 'S' },
	{ "Toggle Full Shields",			HMK_SHIFT_MASK | HK_NUMPAD5 },
	{ "Toggle Front Shields",			HMK_SHIFT_MASK | HK_NUMPAD8 },
	{ "Toggle Right Shields",			HMK_SHIFT_MASK | HK_NUMPAD6 },
	{ "Toggle Aft Shields",				HMK_SHIFT_MASK | HK_NUMPAD2 },
	{ "Toggle Left Shield",				HMK_SHIFT_MASK | HK_NUMPAD4 },
	
	{ "Interdictor",					'I' },
	{ "Mines",							'M' },
	{ "Explode Mines",					HMK_SHIFT_MASK | 'M' },

	{ NULL,								0 }		// leave as last item
};

// this is a list of keys that cannot be assigned to a function
static dword KEYBOARD_EXCLUDE[] = 
{
	HK_ESCAPE,		// escape always should be escape
	HK_SPACE,		// ignore space

	HMK_SHIFT_MASK | HK_SHIFT,
	HMK_CONTROL_MASK | HK_CONTROL,
	HMK_ALT_MASK | HK_MENU,

	'1',			// ignore weapon grouping key assigments
	'2',
	'3',
	'4',
	'5',
	'6',
	'7',
	'8',
	'9',
	'0',

	0
};

static Color BACK_COLORS[] = 
{
	Color( 0, 0, 0 ),
	Color( 80, 88, 127 ),

	WHITE,
	BLACK,
	BLUE,
	RED,
	GREEN,
	DARK_BLUE,
	DARK_RED,
	DARK_GREEN,
	YELLOW,
	DARK_YELLOW,
	GREY,
	LIGHT_GREY,
	MAGENTA,
	CYAN,
	ORANGE,
	PINK,
	CORAL,
	GOLD,
	TAN,
	KHAKI,
	LAVENDER,
	HOTPINK,
	PLUM,
	AQUAMARINE,
	SKYBLUE
};

static Color BORDER_COLORS[] = 
{
	Color( 0, 0, 0 ),
	Color( 191,191,191 ),

	WHITE,
	BLACK,
	BLUE,
	RED,
	GREEN,
	DARK_BLUE,
	DARK_RED,
	DARK_GREEN,
	YELLOW,
	DARK_YELLOW,
	GREY,
	LIGHT_GREY,
	MAGENTA,
	CYAN,
	ORANGE,
	PINK,
	CORAL,
	GOLD,
	TAN,
	KHAKI,
	LAVENDER,
	HOTPINK,
	PLUM,
	AQUAMARINE,
	SKYBLUE
};


//----------------------------------------------------------------------------

IMPLEMENT_FACTORY( ViewOptions, WindowView::View );
REGISTER_FACTORY_KEY( ViewOptions, 4346437673160472801 );

ViewOptions::ViewOptions() : m_KeyRemap( 0 )
{}

//----------------------------------------------------------------------------

void ViewOptions::onActivate()
{
	//{{BEGIN_DATA_INIT
	m_pTextRemap = dynamic_cast<WindowText *>( window()->findNode( "TextRemap" ) );
	m_pDialogRemap = dynamic_cast<NodeWindow *>( window()->findNode( "DialogRemap" ) );
	m_pListKeys = dynamic_cast<WindowList *>( window()->findNode( "ListKeys" ) );
	m_pKeyboardOptions = dynamic_cast<NodeWindow *>( window()->findNode( "KeyboardOptions" ) );
	m_pAudioOptions = dynamic_cast<WindowText *>( window()->findNode( "AudioOptions" ) );
	m_pColorOptions = dynamic_cast<WindowText *>( window()->findNode( "ColorOptions" ) );
	m_pButtonColors = dynamic_cast<WindowButton *>( window()->findNode( "ButtonColors" ) );
	m_pButtonKeyboard = dynamic_cast<WindowButton *>( window()->findNode( "ButtonKeyboard" ) );
	m_pTextSoundVolume = dynamic_cast<WindowText *>( window()->findNode( "TextSoundVolume" ) );
	m_pTextMusicVolume = dynamic_cast<WindowText *>( window()->findNode( "TextMusicVolume" ) );
	//END_DATA_INIT}}

#ifdef _DEBUG
	Settings settings( "ClientD" );
#else
	Settings settings( "Client" );
#endif

	m_pDialogRemap->hideWindow();
	m_pKeyboardOptions->hideWindow();
	m_pAudioOptions->hideWindow();
	m_pColorOptions->showWindow();

	m_pListKeys->setSortEnable( false );
	m_pListKeys->addColumn( 300, WHITE );
	m_pListKeys->addColumn( 100, WHITE );
	m_KeyRemap = 0;

	// load in HUD colors
	dword border = settings.get( "BorderColor", Color( 191,191,191 ).RGB() );
	dword back = settings.get( "BackColor", Color( 80, 88, 127 ).RGB() );

	BORDER_COLORS[ 0 ] = Color( border );
	m_BorderIndex = 0;
	BACK_COLORS[ 0 ] = Color( back );
	m_BackIndex = 0;
}

void ViewOptions::onDeactivate()
{
#ifdef _DEBUG
	Settings settings( "ClientD" );
#else
	Settings settings( "Client" );
#endif

	// make sure keymap is enabled before leaving view
	Keyboard::enableKeyMap();
	// save any changes to the keyboard mapping
	Keyboard::saveKeyMap( settings.get( "keyMap", ".\\keyboard.map" ) );
}

void ViewOptions::onUpdate( float t )
{
	m_pButtonColors->setAlpha( Clamp( m_pButtonColors->alpha() + (m_pColorOptions->visible() ? t : -t), 0.25f, 1.0f ) );
	m_pButtonKeyboard->setAlpha( Clamp( m_pButtonKeyboard->alpha() + (m_pKeyboardOptions->visible() ? t : -t), 0.25f, 1.0f ) );
}

bool ViewOptions::onMessage( const Message & msg )
{
	if ( m_KeyRemap != 0 && msg.message == HM_KEYDOWN )
	{
		dword key = msg.wparam & 0xff;
		if ( key ==	HK_SHIFT || key == HK_CONTROL || key == HK_MENU )
			return true;

		// make sure this isn't an ignore key
		int i = 0;
		while( KEYBOARD_EXCLUDE[ i ] != 0 )
		{
			if ( KEYBOARD_EXCLUDE[ i ] == msg.wparam )
				return true;
			i++;
		}

		Keyboard::enableKeyMap();
		Keyboard::remap( msg.wparam, m_KeyRemap );

		m_KeyRemap = 0;
		updateKeyList();

		m_pDialogRemap->hideWindow();

		return true;
	}

	//{{BEGIN_MSG_MAP
	MESSAGE_MAP( WB_BUTTONUP, 1760410273, onButtonCancelRemap);
	MESSAGE_MAP( WB_BUTTONUP, 2886803252, onButtonRemapKey);
	MESSAGE_MAP( WB_BUTTONUP, 2317609988, onButtonResetKeys);
	MESSAGE_MAP( WB_BUTTONUP, 1362890500, onButtonColors);
	MESSAGE_MAP( WB_BUTTONUP, 2883869073, onButtonKeyboard);
	MESSAGE_MAP( WB_BUTTONUP, 1493398483, onButtonBack);
	MESSAGE_MAP( WB_BUTTONUP, 1792474518, onButtonSoundDown);
	MESSAGE_MAP( WB_BUTTONUP, 362476042, onButtonSoundUp);
	MESSAGE_MAP( WB_BUTTONUP, 2765432743, onButtonMusicDown);
	MESSAGE_MAP( WB_BUTTONUP, 2582213372, onButtonMusicUp);
	MESSAGE_MAP( WB_BUTTONUP, 961758711, onButtonBackDown);
	MESSAGE_MAP( WB_BUTTONUP, 231609188, onButtonBackUp);
	MESSAGE_MAP( WB_BUTTONUP, 908580957, onButtonBorderDown);
	MESSAGE_MAP( WB_BUTTONUP, 1733152323, onButtonBorderUp);
	//END_MSG_MAP}}

	return false;
}

void ViewOptions::onDocumentUpdate()
{
	// document data has changed, update this view if needed
}

//----------------------------------------------------------------------------

void ViewOptions::updateColors( NodeWindow * pWindow, Color border, Color background )
{
	ASSERT( pWindow != NULL );

	static const char * STYLES[] = 
	{
		"HUDSTYLE",
		"HUDSTYLE2",
		"HUDSTYLE3",
		"HUDSTYLE4",
		"HUDSTYLE5", 
		"CONTACTBUTTONSTYLE",
		NULL
	};

	// make sure the alpha is set to full
	border.a = 0xff;
	background.a = 0xff;

	int i = 0;
	while( STYLES[ i ] != NULL )
	{
		WindowStyle * pStyle = dynamic_cast<WindowStyle *>( pWindow->resource( STYLES[ i ] ) );
		if ( pStyle != NULL )
		{
			pStyle->setBorderColor( border );
			pStyle->setBackColor( background );
			pStyle->setScrollColor( background, border );
		}

		i++;
	}
}

void ViewOptions::updateKeyList()
{
	int selected = m_pListKeys->selected();
	int highlighted = m_pListKeys->highlighted();

	m_pListKeys->removeAllItems();

	int i = 0;
	while( KEYBOARD_MAP[ i ].key != 0 )
	{
		dword key = Keyboard::unmap( KEYBOARD_MAP[ i ].key );
		if ( key != 0 )
		{
			int item = m_pListKeys->addItem( KEYBOARD_MAP[ i ].pName );
			m_pListKeys->setItem( item, 1, Keyboard::keyText( key ) );
		}
		else // no valid keyboard assignment
			m_pListKeys->addItem( CharString().format("<color;0000ff>%s</color>", KEYBOARD_MAP[ i ].pName ) );

		i++;
	}

	// restore selected/highlighted items
	m_pListKeys->setSelected( selected );
	m_pListKeys->setHighlighted( highlighted );
}	

//----------------------------------------------------------------------------

bool ViewOptions::onButtonBorderUp(const Message & msg)
{
	m_BorderIndex++;
	if ( m_BorderIndex >= (sizeof( BORDER_COLORS ) / sizeof(Color)) )
		m_BorderIndex = 0;

	updateColors( window(), BORDER_COLORS[ m_BorderIndex ], BACK_COLORS[ m_BackIndex ] );
	return true;
}

bool ViewOptions::onButtonBorderDown(const Message & msg)
{
	m_BorderIndex--;
	if ( m_BorderIndex < 0 )
		m_BorderIndex = (sizeof( BORDER_COLORS ) / sizeof(Color)) - 1;

	updateColors( window(), BORDER_COLORS[ m_BorderIndex ], BACK_COLORS[ m_BackIndex ] );
	return true;
}

bool ViewOptions::onButtonBackUp(const Message & msg)
{
	m_BackIndex++;
	if ( m_BackIndex >= (sizeof( BACK_COLORS ) / sizeof(Color)) )
		m_BackIndex = 0;

	updateColors( window(), BORDER_COLORS[ m_BorderIndex ], BACK_COLORS[ m_BackIndex ] );
	return true;
}

bool ViewOptions::onButtonBackDown(const Message & msg)
{
	m_BackIndex--;
	if ( m_BackIndex < 0 )
		m_BackIndex = (sizeof( BACK_COLORS ) / sizeof(Color)) - 1;

	updateColors( window(), BORDER_COLORS[ m_BorderIndex ], BACK_COLORS[ m_BackIndex ] );
	return true;
}

bool ViewOptions::onButtonMusicUp(const Message & msg)
{
	return true;
}

bool ViewOptions::onButtonMusicDown(const Message & msg)
{
	return true;
}

bool ViewOptions::onButtonSoundUp(const Message & msg)
{
	return true;
}

bool ViewOptions::onButtonSoundDown(const Message & msg)
{
	return true;
}

bool ViewOptions::onButtonBack(const Message & msg)
{
#ifdef _DEBUG
	Settings settings( "ClientD" );
#else
	Settings settings( "Client" );
#endif

	// load in HUD colors
	settings.put( "BorderColor", BORDER_COLORS[ m_BorderIndex ].RGB() );
	settings.put( "BackColor", BACK_COLORS[ m_BackIndex ].RGB() );

	document()->setScene( "Main" );
	return true;
}

bool ViewOptions::onButtonKeyboard(const Message & msg)
{
	m_KeyRemap = 0;
	m_pDialogRemap->hideWindow();
	m_pKeyboardOptions->showWindow();
	m_pAudioOptions->hideWindow();
	m_pColorOptions->hideWindow();

	updateKeyList();
	return true;
}

bool ViewOptions::onButtonColors(const Message & msg)
{
	m_KeyRemap = 0;
	m_pDialogRemap->hideWindow();
	m_pKeyboardOptions->hideWindow();
	m_pAudioOptions->hideWindow();
	m_pColorOptions->showWindow();
	return true;
}

bool ViewOptions::onButtonResetKeys(const Message & msg)
{
	Keyboard::resetKeyMap();
	updateKeyList();
	return true;
}

bool ViewOptions::onButtonRemapKey(const Message & msg)
{
	int selected = m_pListKeys->selected();
	if ( selected >= 0 )
	{
		m_KeyRemap = KEYBOARD_MAP[ selected ].key;
		m_pTextRemap->setText( CharString().format("Press KEY assignment for %s", KEYBOARD_MAP[ selected ].pName) );
		m_pDialogRemap->showWindow();

		// disable the keymap
		Keyboard::disableKeyMap();
	}
	return true;
}

bool ViewOptions::onButtonCancelRemap(const Message & msg)
{
	// enable keyboard remapping
	Keyboard::enableKeyMap();
	// reset remap
	m_KeyRemap = 0;
	m_pDialogRemap->hideWindow();

	return true;
}

